#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
   文件名称 :     jwt_helper
   文件功能描述 :   功能描述
   创建人 :       小钟同学
   创建时间 :          2022/2/11
-------------------------------------------------
   修改描述-2022/2/11:         
-------------------------------------------------
"""
import hashlib

import jwt
import datetime

from passlib.context import CryptContext


class Auth():
    # 签名秘钥
    secret = 'XXXXXXXXXXXXXXXXXX'
    # iss: 该JWT的签发者，是否使用是可选的；
    iss = 'erasd4w2ddwr324'
    aud = 'ASKEDASM34IOASDKRFN'
    pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

    def __init__(self):
        pass

    @classmethod
    def create_token(cls, sub='', data={}, scopes=['open'], exp_time=60 * 60 * 24 * 5):
        """
        生成对应的JWT的token值
        :param sub:    参数名称
        :param data:      参与签名的参数信息
        :param secret:   是否要求进行空检测，True必须检测
        :param exp_time:  token过期时间，按秒来计算
        :return:        返回处理后的参数
        """
        if not data:
            return False, {'access_token': '', 'meg': '需要签名信息不能为空'}

        payload = {
            "iss": cls.iss,  # iss: 该JWT的签发者，是否使用是可选的；
            "exp": datetime.datetime.utcnow() + datetime.timedelta(days=0, seconds=exp_time),
            # 什么时候过期，这里是一个Unix时间戳，是否使用是可选的；
            "iat": datetime.datetime.utcnow(),  # 在什么时候签发的(UNIX时间)，是否使用是可选的；
            "aud": cls.aud,  # 接收该JWT的一方，是否使用是可选的；#  如果在生成token的时候使用了aud参数，那么校验的时候也需要添加此参数
            "sub": sub,  # sub: 该JWT所面向的用户，是否使用是可选的；
            "scopes": scopes,  # 用户授权的作用域，使用逗号（,）分隔
            "data": data
        }
        # 不参与进行签名计算
        if not sub:
            payload.pop('sub')
        # token生成处理
        token = jwt.encode(payload, cls.secret, algorithm='HS256')
        # 返回授权token
        return True, token

    @classmethod
    def verify_bearer_token(cls, ischecck_sub=False, sub_in='', token=''):
        #  如果在生成token的时候使用了aud参数，那么校验的时候也需要添加此参数
        try:
            payload = jwt.decode(token, cls.secret, audience=cls.aud, algorithms=['HS256'])
            if ischecck_sub and sub_in != '':
                sub = payload['sub']
                if sub != sub_in:
                    return False, "无效的Token"

            if payload and ('data' in payload):
                # 验证通过返回对应的参与签名的字段信息
                return True, payload['data']
            else:
                raise jwt.InvalidTokenError

        except jwt.ExpiredSignatureError:
            return False, "Token过期"

        except jwt.InvalidTokenError:
            return False, "无效的Token"
        except:
            return False, "无效的Token"

    @classmethod
    def verify_bearer_token_state(cls, ischecck_sub=False, sub_in='', token=''):
        #  如果在生成token的时候使用了aud参数，那么校验的时候也需要添加此参数
        try:
            payload = jwt.decode(token, cls.secret, audience=cls.aud, algorithms=['HS256'])
            if ischecck_sub and sub_in != '':
                sub = payload['sub']
                if sub != sub_in:
                    return False, 1, "无效的Token"

            if payload and ('data' in payload):
                # 验证通过返回对应的参与签名的字段信息
                return True, 0, payload['data']
            else:
                raise jwt.InvalidTokenError

        except jwt.ExpiredSignatureError:
            return False, 2, "Token过期"

        except jwt.InvalidTokenError:
            return False, 1, "无效的Token"
        except:
            return False, 1, "无效的Token"

    @classmethod
    def verify_password(cls, plain_password, hashed_password):
        return cls.pwd_context.verify(plain_password, hashed_password)

    @classmethod
    def get_password_hash(cls, password):
        return cls.pwd_context.hash(password)

    @staticmethod
    def creat_password_salt(password, salt):
        '''
        生成加盐秘钥
        :param password:
        :param salt:
        :return:
        '''
        m = hashlib.md5()
        bt = f"{password}{salt}".encode("utf-8")
        m.update(bt)
        return m.hexdigest()


import jwt
import datetime


class SimpleAuth():
    # 签名秘钥
    secret = 'xxxxxxxxxxxxxx '
    # iss: 该JWT的签发者，是否使用是可选的；
    iss = 'xxxxxxxxxxxxxxxxxxxxx'
    aud = 'xxxxxxxxxxxxxxxxxxxxxx'

    def __init__(self):
        pass

    # 1000天有效期
    @classmethod
    def create_token_by_data(cls, sub='', data={}, scopes=['open'], exp_time=60 * 60 * 24 * 5):
        """
        生成对应的JWT的token值
        :param sub:    参数名称
        :param data:      参与签名的参数信息
        :param secret:   是否要求进行空检测，True必须检测
        :param exp_time:  token过期时间，按秒来计算
        :return:        返回处理后的参数
        """
        if not data:
            return False, {'access_token': '', 'meg': '需要签名信息不能为空'}

        payload = {
            "iss": cls.iss,  # iss: 该JWT的签发者，是否使用是可选的；
            "exp": datetime.datetime.utcnow() + datetime.timedelta(days=0, seconds=exp_time),  # 什么时候过期，这里是一个Unix时间戳，是否使用是可选的；
            "iat": datetime.datetime.utcnow(),  # 在什么时候签发的(UNIX时间)，是否使用是可选的；
            "aud": cls.aud,  # 接收该JWT的一方，是否使用是可选的；#  如果在生成token的时候使用了aud参数，那么校验的时候也需要添加此参数
            "sub": sub,  # sub: 该JWT所面向的用户，是否使用是可选的；
            "scopes": scopes,  # 用户授权的作用域，使用逗号（,）分隔
            "data": data
        }
        # 不参与进行签名计算
        if not sub:
            payload.pop('sub')
        # token生成处理
        token = jwt.encode(payload, cls.secret, algorithm='HS256')
        # 返回授权token
        return True, token

    @classmethod
    def verify_bearer_token(cls, ischecck_sub=False, sub_in='', token=''):
        #  如果在生成token的时候使用了aud参数，那么校验的时候也需要添加此参数
        try:
            payload = jwt.decode(token, cls.secret, audience=cls.aud, algorithms=['HS256'])
            if ischecck_sub and sub_in != '':
                sub = payload['sub']
                if sub != sub_in:
                    return False, "无效的Token"

            if payload and ('data' in payload):
                # 验证通过返回对应的参与签名的字段信息
                return True, payload['data']
            else:
                raise jwt.InvalidTokenError

        except jwt.ExpiredSignatureError:
            return False, "Token过期"

        except jwt.InvalidTokenError:
            return False, "无效的Token"
        except:
            return False, "无效的Token"

    @classmethod
    def verify_bearer_token_state(cls, ischecck_sub=False, sub_in='', token=''):
        #  如果在生成token的时候使用了aud参数，那么校验的时候也需要添加此参数
        try:
            payload = jwt.decode(token, cls.secret, audience=cls.aud, algorithms=['HS256'])
            if ischecck_sub and sub_in != '':
                sub = payload['sub']
                if sub != sub_in:
                    return False, 1, "无效的Token"

            if payload and ('data' in payload):
                # 验证通过返回对应的参与签名的字段信息
                return True, 0, payload['data']
            else:
                raise jwt.InvalidTokenError

        except jwt.ExpiredSignatureError:
            return False, 2, "Token过期"

        except jwt.InvalidTokenError:
            return False, 1, "无效的Token"
        except:
            return False, 1, "无效的Token"

